////////////////////////////////////////////////////////////////////////////////
//  Filename      : CRC.bsv
//  Description   : Generalized implementation of CRC algorithms
////////////////////////////////////////////////////////////////////////////////
package CRC;

// Notes :

////////////////////////////////////////////////////////////////////////////////
/// Functions
////////////////////////////////////////////////////////////////////////////////
function Bit#(a) reflect(Bool doIt, Bit#(a) data);
   return (doIt) ? reverseBits(data) : data;
endfunction

////////////////////////////////////////////////////////////////////////////////
/// Interfaces
////////////////////////////////////////////////////////////////////////////////
interface CRC#(numeric type n);
   method    Action   add(Bit#(8) data);
   method    Action   clear();
   method    Bit#(n)  result();
   method    ActionValue#(Bit#(n)) complete();
endinterface

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///
/// Implementation of generalized CRC module
///
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
module mkCRC#(  Bit#(n) polynomial       // the crc operation x^16 + x^12 + x^5 + 1 = 'h1021
              , Bit#(n) initval          // the initial CRC value
              , Bit#(n) finalXor         // the result is xor'd with this value if desired
              , Bool    reflectData      // reverse the data bit order
              , Bool    reflectRemainder // reverse the result bit order
              )(CRC#(n))
   provisos(  Add#(8, n8, n)             // CRCs less than 8 bits are not permitted with this module
            );

   ////////////////////////////////////////////////////////////////////////////////
   /// Design Elements
   ////////////////////////////////////////////////////////////////////////////////
   Reg#(Bit#(n))         rRemainder          <- mkReg(initval);
   RWire#(Bit#(8))       rwAddIn             <- mkRWire;
   PulseWire             pwClear             <- mkPulseWire;
   PulseWire             pwComplete          <- mkPulseWire;

   ////////////////////////////////////////////////////////////////////////////////
   /// Rules
   ////////////////////////////////////////////////////////////////////////////////
   (* fire_when_enabled *)
   rule update_crc;
      if (pwClear || pwComplete)
         rRemainder <= initval;
      else if (rwAddIn.wget matches tagged Valid .data) begin
         Bit#(n) remainder = rRemainder ^ (zeroExtend(reflect(reflectData, data)) << valueOf(n8));
         for(Integer i = 0; i < 8; i = i + 1) begin
            if (msb(remainder) == 1) remainder = (remainder << 1) ^ polynomial;
            else                     remainder = (remainder << 1);
         end
         rRemainder <= remainder;
      end
   endrule

   ////////////////////////////////////////////////////////////////////////////////
   /// Interface Connections / Methods
   ////////////////////////////////////////////////////////////////////////////////
   method Action add(data);
      rwAddIn.wset(data);
   endmethod

   method Action clear();
      pwClear.send;
   endmethod

   method Bit#(n) result();
      return reflect(reflectRemainder, rRemainder) ^ finalXor;
   endmethod

   method ActionValue#(Bit#(n)) complete();
      pwComplete.send;
      return reflect(reflectRemainder, rRemainder) ^ finalXor;
   endmethod

endmodule

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///
/// Implementation of the CRC-CCITT standard (x^16 + x^12 + x^5 + 1)
///
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
(* synthesize *)
module mkCRC_CCITT(CRC#(16));
   (* hide *)
   let _m <- mkCRC('h1021, 'hFFFF, 'h0000, False, False);
   return _m;
endmodule

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///
/// Implementation of the CRC-16-ANSI standard (x^16 + x^15 + x^2 + 1)
///
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
(* synthesize *)
module mkCRC16(CRC#(16));
   (* hide *)
   let _m <- mkCRC('h8005, 'h0000, 'h0000, True, True);
   return _m;
endmodule

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///
/// Implementation of the CRC-32 (IEEE 802.3) standard
/// (x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1)
///
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
(* synthesize *)
module mkCRC32(CRC#(32));
   (* hide *)
   let _m <- mkCRC('h04C11DB7, 'hFFFFFFFF, 'hFFFFFFFF, True, True);
   return _m;
endmodule

endpackage: CRC
